package com.learn.cloud.validator.annotation;

import cn.hutool.core.util.ObjectUtil;
import jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.Payload;
import lombok.SneakyThrows;
import java.lang.annotation.*;
import java.lang.reflect.Method;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @description: 枚举值校验
 * @author: cong zhi
 * @createDate: 2022/2/10 17:55
 * @updateUser: cong zhi
 * @updateDate: 2022/2/10 17:55
 * @updateRemark: 修改内容
 * @version: v1.0
 */
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {Enum.EnumConstraintValidator.class})
@Repeatable(Enum.List.class)
public @interface Enum {

    /**
     * 枚举的类型
     *
     * @return
     */
    Class<?> value();

    /**
     * 错误消息
     *
     * @return
     */
    String message() default "{javax.validation.constraints.Enum.message}";

    /**
     * 调用的方法
     *
     * @return
     */
    String method() default "getValue";

    /**
     * 分组
     *
     * @return
     */
    Class<?>[] groups() default {};

    /**
     * 拓展对象
     *
     * @return
     */
    Class<? extends Payload>[] payload() default {};

    /**
     * 必须实现EnumValidator接口枚举类
     *
     * @return
     */
    Class<? extends EnumConstraintValidator> clazz();

    /**
     * Defines several {@code @In} constraints on the same element.
     *
     * @see Enum
     */
    @Target({FIELD, ElementType.PARAMETER})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        /**
         * 数组
         *
         * @return
         */
        Enum[] value();
    }

    /**
     * @description:    枚举验证器实现
     * @author:         cong zhi
     * @createDate:     2022/2/11 10:06
     * @updateUser:     cong zhi
     * @updateDate:     2022/2/11 10:06
     * @updateRemark:   修改内容
     * @version:        v1.0
     */
    class EnumConstraintValidator implements ConstraintValidator<Enum, Object> {

        /**
         * 注解对象
         */
        private Enum annotation;


        @Override
        public void initialize(Enum constraintAnnotation) {
            this.annotation = constraintAnnotation;
        }

        @SneakyThrows
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            if (ObjectUtil.isNull(value)) {
                return Boolean.FALSE;
            }

            Object[] enumConstants = annotation.clazz().getEnumConstants();
            // 核心代码实现
            Method method = annotation.clazz().getMethod(annotation.method());
            for (Object enumConstant : enumConstants) {
                if (value.equals(method.invoke(enumConstant))) {
                    return Boolean.TRUE;
                }
            }
            return Boolean.FALSE;
        }
    }
}
